﻿using System;
#if DEBUG
using System.Diagnostics;
#endif // #if DEBUG
using System.Net;
using System.Text;

using FRL.DebtChased.Extensions;
using FRL.DebtChased.Repository;

namespace FRL.DebtChased.Types
{

	/// <summary>
	/// Declaration of Frequency class
	/// </summary>
	public class Frequency
	{

		/////////////////////////////////////////////////////////////
		// Enumerations

		[Flags]
		public enum ePeriod
		{

			NotSet = 0,

			Weekly = 0x01,
			Biweekly = 0x02,
			Monthly = 0x04,
			PeriodMask = 0x0F,

			Monthly_ByDate = 0x100,
			Monthly_ByWeek = 0x200,
			Monthly_Param_Mask = 0xF00,

		}

		/////////////////////////////////////////////////////////////
		// Attributes

		private ePeriod m_PeriodFlags = ePeriod.NotSet;
		public ePeriod PeriodFlags
		{
			get { return m_PeriodFlags; }
			set { m_PeriodFlags = value; }
		}
		public bool IsWeekly
		{
			get { return (m_PeriodFlags & ePeriod.Weekly) == ePeriod.Weekly; }
		}
		public bool IsBiweekly
		{
			get { return (m_PeriodFlags & ePeriod.Biweekly) == ePeriod.Biweekly; }
		}
		public bool IsMonthly
		{
			get { return (m_PeriodFlags & ePeriod.Monthly) == ePeriod.Monthly; }
		}
		public bool IsMonthlyByDate
		{
			get { return (m_PeriodFlags & ePeriod.Monthly_ByDate) == ePeriod.Monthly_ByDate; }
		}
		public bool IsMonthlyByWeek
		{
			get { return (m_PeriodFlags & ePeriod.Monthly_ByWeek) == ePeriod.Monthly_ByWeek; }
		}

		private DateTime m_dtStart;
		public DateTime Start
		{
			get { return m_dtStart; }
			set { m_dtStart = value; }
		}

		/////////////////////////////////////////////////////////////
		// Construction

		public Frequency(ePeriod PeriodFlags, DateTime dtStart)
		{

			// Initialize member variables
			m_PeriodFlags = PeriodFlags;
			m_dtStart = dtStart;

		}

		/////////////////////////////////////////////////////////////
		// Operations

		public string ComposeDescription()
		{

			// Build description
			StringBuilder sb = new StringBuilder();

			// Compare periods
			if(IsWeekly)
				sb.AppendFormat("Weekly, every {0}",
					m_dtStart.DayOfWeek.ToString()
				);
			else if(IsBiweekly)
				sb.AppendFormat("Biweekly, every other {0}",
					m_dtStart.DayOfWeek.ToString()
				);
			else if(IsMonthly)
			{
				if (IsMonthlyByDate)
					sb.AppendFormat("Monthly, the {0} of the month",
						m_dtStart.Day.ToShortGenetive()
					);
				else
					sb.AppendFormat("Monthly, every {0} {1}",
						ExtensionsForDates.CountWeekDay(m_dtStart).ToShortGenetive(),
						m_dtStart.DayOfWeek
					);
			}
#if DEBUG
			else
				Debug.Assert(false);
#endif // #if DEBUG

			// Return string
			return sb.ToString();

		}

		public DateTime CalculateNthPayment(int iPaymentOffset)
		{

			// Shortcuts
			if (iPaymentOffset == 0)
				return m_dtStart;

			// Declare return variable
			DateTime dtFtmp = m_dtStart;

			// Compare periods
			if (this.IsWeekly)
			{

				// Add weeks
				dtFtmp = dtFtmp.AddDays(iPaymentOffset * 7);

			}
			else if (this.IsBiweekly)
			{

				// Add bi-weeks
				dtFtmp = dtFtmp.AddDays(iPaymentOffset * 14);

			}
			else if (this.IsMonthly)
			{

				// Get to first of the month
				dtFtmp = new DateTime(m_dtStart.Year, m_dtStart.Month, 1);
				dtFtmp = dtFtmp.AddMonths(iPaymentOffset);

				// If monthly by date...
				if (this.IsMonthlyByDate)
				{

					// Compose date
					int iDay = Math.Min(m_dtStart.Day, DateTime.DaysInMonth(dtFtmp.Year, dtFtmp.Month));
					dtFtmp = new DateTime(dtFtmp.Year, dtFtmp.Month, iDay);

				}
				else if (this.IsMonthlyByWeek)
				{

					// Count the genetive
					int iGenetive = ExtensionsForDates.CountWeekDay(m_dtStart);

					// Loop through week
					dtFtmp = ExtensionsForDates.CalculateDate(dtFtmp.Year, dtFtmp.Month, iGenetive, m_dtStart.DayOfWeek);

				}
#if DEBUG
				else
					Debug.Assert(false);
#endif // #if DEBUG

			}
#if DEBUG
			else
				Debug.Assert(false);
#endif // #if DEBUG

			// Return variable
			return dtFtmp;

		}

	}

}
